<template>
  <div>
    <textarea ref="textarea" :id="id"></textarea>
    <el-dialog :visible.sync="showDialogUploadImage" title="批量上传图片" :append-to-body="true">
      <UploadImage v-if="showDialogUploadImage" :infoType="infoType" @close="showDialogUploadImage = false" @success="handleimageUploadSuccess" />
    </el-dialog>
    <el-dialog :visible.sync="showDialogUploadFile" title="批量上传附件" :append-to-body="true">
      <UploadFile v-if="showDialogUploadFile" :infoType="infoType" @close="showDialogUploadFile = false" @success="handleFileUploadSuccess" />
    </el-dialog>
  </div>
</template>

<script>
import tinymce from 'tinymce/tinymce'
import 'tinymce/skins/ui/oxide/skin'
import 'tinymce/themes/silver/theme'
import 'tinymce/icons/default/icons'
import 'tinymce/models/dom/model'
import 'tinymce/plugins/advlist'
import 'tinymce/plugins/autolink'
import 'tinymce/plugins/code'
import 'tinymce/plugins/directionality'
import 'tinymce/plugins/fullscreen'
import 'tinymce/plugins/insertdatetime'
import 'tinymce/plugins/link'
import 'tinymce/plugins/anchor'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/media'
import 'tinymce/plugins/nonbreaking'
import 'tinymce/plugins/pagebreak'
import 'tinymce/plugins/preview'
import 'tinymce/plugins/searchreplace'
import 'tinymce/plugins/table'
import 'tinymce/plugins/visualblocks'
import 'tinymce/plugins/visualchars'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/image'

import UploadImage from './components/UploadImage'
import UploadFile from './components/UploadFile'
import { upyunUpload } from '@/utils/upyun'
import { apitextGetFile } from '@/api/api'

export default {
  name: 'TinyMCE',
  components: { UploadImage, UploadFile },
  props: {
    id: {
      type: String,
      default: function () {
        return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
      },
    },
    value: {
      type: String,
      default: '',
    },
    height: {
      type: [Number, String],
      required: false,
      default: 360,
    },
    infoType: {
      type: String,
      default: 'asset',
    },
  },
  data() {
    return {
      editor: null,
      showDialogUploadImage: false,
      showDialogUploadFile: false,
      globalIdCounter: 0,
    }
  },
  watch: {
    value: {
      handler() {
        this.setValue(this.value)
      },
      immediate: true,
    },
  },
  mounted() {
    this.init()
  },
  beforeDestroy() {
    this.editor?.destroy()
  },
  methods: {
    init() {
      const _this = this
      tinymce
        .init({
          target: this.$refs.textarea,
          height: this.height,
          ui_mode: 'split',
          license_key: 'gpl',
          content_css: '/tinymce7/skins/ui/oxide/content.css',
          language_url: '/tinymce7/langs/zh_CN.js',
          language: 'zh_CN',
          plugins: 'lists link anchor code wordcount image table visualchars visualblocks searchreplace preview pagebreak nonbreaking media insertdatetime fullscreen directionality autolink advlist',
          toolbar: [
            'unlink removeformat |fontfamily fontsize fontsizeselect blocks | bold italic underline strikethrough superscript subscript backcolor forecolor | numlist bullist ',
            ' alignleft aligncenter alignright alignjustify lineheight outdent indent | undo redo searchreplace fullscreen | link image media uploadimages uploadfiles | preview code',
          ],
          // 字体
          font_family_formats:
            '宋体=SimSun; 微软雅黑=Microsoft Yahei; 新宋体=NSimSun; 黑体=SimHei; 楷体=KaiTi; 仿宋=FangSong; 微软正黑体=Microsoft JhengHei; Andale Mono=andale mono,times; Arial=arial,helvetica,sans-serif; Arial Black=arial black,avant garde; Book Antiqua=book antiqua,palatino; Comic Sans MS=comic sans ms,sans-serif; Courier New=courier new,courier; Georgia=georgia,palatino; Helvetica=helvetica; Impact=impact,chicago; Symbol=symbol; Tahoma=tahoma,arial,helvetica,sans-serif; Terminal=terminal,monaco; Times New Roman=times new roman,times; Trebuchet MS=trebuchet ms,geneva; Verdana=verdana,geneva; Webdings=webdings; Wingdings=wingdings,zapf dingbats',
          // 字体大小
          font_size_formats: '8px 10px 12px 14px 16px 18px 20px 22px 24px 26px 28px 36px 48px 72px',
          font_size_input_default_unit: 'px',
          promotion: false,
          formats: {
            removeformat: [
              {
                selector: 'h1,h2,h3,h4,h5,h6',
                remove: 'all',
                split: false,
                expand: false,
                block_expand: true,
                deep: true,
              },
              {
                selector: 'b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small, a',
                remove: 'all',
                split: true,
                expand: false,
                deep: true,
              },
              { selector: 'span', attributes: ['style', 'class'], remove: 'empty', split: true, expand: false, deep: true },
              { selector: '*', attributes: ['style', 'class'], split: false, expand: false, deep: true },
            ],
          },
          // 图片上传
          images_upload_handler: (blobInfo, progress) => {
            return new Promise((resolve, reject) => {
              var file = blobInfo.blob()
              upyunUpload({ file, watermark: true, info_type: _this.infoType })
                .then((res) => {
                  if (res) {
                    resolve(res)
                  }
                })
                .catch(() => {
                  reject('HTTP Error')
                })
            })
          },
          // 文件上传
          file_picker_callback: (callback, value, meta) => {
            const _this = this
            //文件分类
            var filetype = '.pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4'
            //为不同插件指定文件类型及后端地址
            switch (meta.filetype) {
              case 'image':
                filetype = '.jpg, .jpeg, .png, .gif'
                break
              case 'media':
                filetype = '.mp3, .mp4'
                break
              case 'file':
              default:
            }
            //模拟出一个input用于添加本地文件
            var input = document.createElement('input')
            input.setAttribute('type', 'file')
            input.setAttribute('accept', filetype)
            input.click()
            input.onchange = function () {
              var file = this.files[0]
              upyunUpload({ file, watermark: false, info_type: _this.infoType }).then((res) => {
                if (res) {
                  callback(res, { text: file.name })
                }
              })
            }
          },
          // 处理粘贴图片
          paste_preprocess: (editor, args) => {
            const { content } = args
            _this.globalIdCounter++
            const whiteList = ['https://img5.feijiu.net', 'https://recycleimg.feijiu.net']
            let imgList = content.match(/\<img.*?\>/g)
            let srcList = []
            if (imgList) {
              imgList.forEach((item, index) => {
                let srcMatchList = item.match(/src=".*?"/g)
                if (srcMatchList) {
                  let srcMatch = srcMatchList[0]
                  let srcString = srcMatch.split('"')[1]
                  srcList.push({
                    id: '' + _this.globalIdCounter + index,
                    src: srcString,
                  })
                  args.content = args.content.replace(srcMatch, ' id="pasted_image_' + _this.globalIdCounter + index + '" ' + srcMatch)
                }
              })
              srcList.forEach((item) => {
                let needUplod = true
                whiteList.forEach((whiteListItem) => {
                  if (item.src.includes(whiteListItem)) {
                    needUplod = false
                  }
                })
                if (!item.src.match(/^http/)) {
                  needUplod = false
                }
                if (needUplod) {
                  // -1资产2公告
                  apitextGetFile({ url: item.src, info_type: this.infoType === 'asset' ? 1 : 2 }).then((res) => {
                    // 修改dom，还要直接改content
                    const id = item.id
                    document
                      .getElementsByClassName('tox-edit-area__iframe')[0]
                      .contentWindow.document.getElementById('pasted_image_' + id)
                      .setAttribute('src', res.url)
                    let content = editor.getContent()
                    _this.setValue(content.replaceAll(item.src, res.url))
                  })
                }
              })
            }
          },
          setup(editor) {
            // 批量上传图片
            editor.ui.registry.addButton('uploadimages', {
              text: '批量上传', // 按钮文本
              icon: 'image',
              tooltip: '批量上传图片', // 鼠标悬停时显示的工具提示
              onAction: function () {
                // 按钮点击时执行的操作
                _this.showDialogUploadImage = true
              },
            })
            // 批量上传附件
            editor.ui.registry.addButton('uploadfiles', {
              text: '批量上传', // 按钮文本
              icon: 'upload',
              tooltip: '批量上传文件', // 鼠标悬停时显示的工具提示
              onAction: function () {
                // 按钮点击时执行的操作
                _this.showDialogUploadFile = true
              },
            })
          },
        })
        .then(([editor]) => {
          this.editor = editor
          this.setValue(this.value)
          editor.on('change keyup undo redo', () => {
            this.$emit('input', editor.getContent())
          })
        })
    },
    setValue(val) {
      const oldValue = this.editor?.getContent()
      if (typeof val === 'string' && val !== oldValue) {
        this.editor?.setContent(val)
      }
    },
    destroyTinymce() {
      this.editor?.destroy()
    },
    getContent() {
      this.editor?.getContent()
    },
    insertContent(content) {
      // 获取富文本编辑器
      var range = this.editor.selection.getRng()

      // 创建要插入的内容
      var divNode = this.editor.getDoc().createElement('div')
      const realStr = content
      divNode.innerHTML = realStr
      range.insertNode(divNode)
    },
    handleimageUploadSuccess(arr) {
      this.showDialogUploadImage = false
      arr.forEach((v) => this.editor.insertContent(`<img class="wscnph" src="${v.url}" >`))
    },
    handleFileUploadSuccess(arr) {
      this.showDialogUploadFile = false

      arr.forEach((item) => {
        if (item.response) {
          this.editor.insertContent(`<p><a href="${item.response}" target="_blank" rel="noopener">${item.name}</a></p>`)
        }
      })
    },
    // 重置
    reset() {
      this.editor?.setContent('')
    },
  },
}
</script>

<style>
.tox-tinymce-aux {
  z-index: 10000 !important;
}
.tox .tox-number-input .tox-input-wrapper {
  display: none !important;
}
.tox-statusbar__branding {
  display: none !important;
}

.tox .tox-tbtn svg {
  fill: #666 !important;
}

.tox .tox-edit-area::before {
  border: 1px solid #5db42c !important;
}
.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) {
  background-color: #5db42c !important;
}
.tox .tox-mbtn--active,
.tox .tox-mbtn:not(:disabled).tox-mbtn--active:focus {
  background: #cfe7c1 !important;
}
.tox .tox-mbtn:focus:not(:disabled)::after {
  box-shadow: 0 0 0 2px #5db42c !important;
}
.tox .tox-tbtn--active,
.tox .tox-tbtn--enabled,
.tox .tox-tbtn--enabled:focus,
.tox .tox-tbtn--enabled:hover,
.tox .tox-tbtn:active {
  background: #cfe7c1 !important;
}
.tox .tox-tbtn::after,
.tox-split-button::after,
.tox .tox-tbtn--enabled:focus::after {
  box-shadow: 0 0 0 2px #5db42c !important;
}
.tox .tox-collection--toolbar .tox-collection__item--enabled:not(.tox-collection__item--state-disabled) {
  background: #cfe7c1 !important;
}
.tox-menu-nav__js:hover::after,
.tox-collection__item--active::after {
  box-shadow: 0 0 0 2px #5db42c !important;
}
.tox .tox-button {
  background-color: #5db42c !important;
  border: none !important;
}
.tox .tox-button--naked {
  background-color: transparent !important;
}
.tox .tox-button--secondary {
  background-color: #f0f0f0 !important;
}
.tox .tox-button:hover:not(:disabled) {
  background-color: #5db42c !important;
}
.tox .tox-button::before {
  box-shadow: inset 0 0 0 1px #fff, 0 0 0 2px #5db42c !important;
}
.tox .tox-dialog__body-nav-item--active {
  border-bottom: 2px solid #5db42c !important;
  color: #5db42c !important;
}
.tox .tox-custom-editor:focus-within,
.tox .tox-listboxfield .tox-listbox--select:focus,
.tox .tox-textarea-wrap:focus-within,
.tox .tox-textarea:focus,
.tox .tox-textfield:focus {
  border-color: #5db42c !important;
  box-shadow: 0 0 0 1px #5db42c !important;
}
</style>
